package cn.wen.xframe.monitor;

import java.lang.management.ManagementFactory;
import java.lang.management.MemoryPoolMXBean;
import java.lang.management.MemoryUsage;
import java.text.DecimalFormat;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

import cn.wen.bases.framework.struts.action.ActionSupport;
import cn.wen.bases.framework.struts.action.model.AbstractModel;

/**
 * Title：内存信息
 * <p>
 * Description：
 * <p>
 * Copyright：Copyright (c) 2010-2012
 * 
 * @author <a href="mailto:ct_wen@qq.com">ctwen</a>, 温承瑭
 * @version Revision：1.0 Date：2012/12/5 Description：初完成。
 *          <p>
 */
public class MemoryAction extends ActionSupport {

    private MemoryModel model = new MemoryModel();

    @Override
    public Object getModel() {
	return model;
    }

    @Override
    public String execute() throws Exception {
	model.memory.put("heap", asMap(model.usageHeapMemory));
	model.memory.put("heap_tenured", asMap(model.usageHeapTenuredGen));
	model.memory.put("heap_eden", asMap(model.usageHeapEdenSpace));
	model.memory.put("heap_survivor", asMap(model.usageHeapSurvivorSpace));
	
	model.memory.put("nonHeap", asMap(model.usageNonHeapMemory));
	model.memory.put("nonHeap_perm", asMap(model.usageNonHeapPermGen));
	model.memory.put("nonHeap_code", asMap(model.usageNonHeapCodeCache));

	return super.execute();
    }

    private Map<String, Object> asMap(MemoryUsage usage) {
	Map<String, Object> usageMap = new HashMap<String, Object>();

	usageMap.put("init", b2m(usage.getInit()));
	usageMap.put("max", b2m(usage.getMax()));
	usageMap.put("committed", b2m(usage.getCommitted()));
	
	usageMap.put("used", b2m(usage.getUsed()));
	usageMap.put("useRatio", ratio(usage.getUsed() / (double) usage.getCommitted()));
	usageMap.put("useMaxRatio", ratio(usage.getUsed() / (double) usage.getMax()));
	
	long free = usage.getCommitted() - usage.getUsed();
	usageMap.put("free", b2m(free));
	usageMap.put("freeRatio", ratio(free / (double) usage.getCommitted()));
	free = usage.getMax() - usage.getUsed();
	usageMap.put("freeMax", b2m(free));
	usageMap.put("freeMaxRatio", ratio(free / (double) usage.getMax()));
	
	String prompt = null;
	if (usage.getUsed() / (double) usage.getMax() >= 0.75) {
	    prompt = "警告！已用空间超出安全区域，启用应急空间，请查看线程堆栈跟踪情况。";
	}
	else {
	    prompt = "处于安全区域。";
	}
	usageMap.put("prompt", prompt);

	return usageMap;
    }

    private DecimalFormat df1 = new DecimalFormat("#,##0.#");
    private DecimalFormat df2 = new DecimalFormat("0.#%");

    /**
     * 字节 转 兆字节
     */
    private String b2m(long bytes) {
	return df1.format(bytes / Math.pow(1024, 2));
    }
    
    private String ratio(double ratio) {
	return df2.format(ratio);
    }

}

class MemoryModel extends AbstractModel {

    public MemoryModel() {
	super();

    }

    Map<String, Map<String, Object>> memory = new LinkedHashMap<String, Map<String, Object>>(7);

    /**
     * 堆
     */
    MemoryUsage usageHeapMemory = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage();
    /**
     * 伊甸园（年轻代）
     */
    MemoryUsage usageHeapEdenSpace = MonitorUtil.getMemoryPoolMXBean("Eden Space").getUsage();
    /**
     * 幸存者（年轻代）
     */
    MemoryUsage usageHeapSurvivorSpace = MonitorUtil.getMemoryPoolMXBean("Survivor Space").getUsage();
    /**
     * 老年代
     */
    MemoryUsage usageHeapTenuredGen = getTenuredMemoryPoolMXBean().getUsage();
    private MemoryPoolMXBean getTenuredMemoryPoolMXBean() {
	MemoryPoolMXBean memoryPool = MonitorUtil.getMemoryPoolMXBean("Tenured Gen");
	if (memoryPool == null) memoryPool = MonitorUtil.getMemoryPoolMXBean("Old Gen");
	return memoryPool;
    }

    /**
     * 非堆
     */
    MemoryUsage usageNonHeapMemory = ManagementFactory.getMemoryMXBean().getNonHeapMemoryUsage();
    /**
     * 代码缓存
     */
    MemoryUsage usageNonHeapCodeCache = MonitorUtil.getMemoryPoolMXBean("Code Cache").getUsage();
    /**
     * 永久代（方法区）
     */
    MemoryUsage usageNonHeapPermGen = MonitorUtil.getMemoryPoolMXBean("Perm Gen").getUsage();

    public Map<String, Map<String, Object>> getMem() {
	return memory;
    }

    public MemoryUsage getUsageHeapMemory() {
	return usageHeapMemory;
    }

    public MemoryUsage getUsageHeapEdenSpace() {
	return usageHeapEdenSpace;
    }

    public MemoryUsage getUsageHeapSurvivorSpace() {
	return usageHeapSurvivorSpace;
    }

    public MemoryUsage getUsageHeapTenuredGen() {
	return usageHeapTenuredGen;
    }

    public MemoryUsage getUsageNonHeapMemory() {
	return usageNonHeapMemory;
    }

    public MemoryUsage getUsageNonHeapCodeCache() {
	return usageNonHeapCodeCache;
    }

    public MemoryUsage getUsageNonHeapPermGen() {
	return usageNonHeapPermGen;
    }

}
